home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr49 / 106_01.zip / STDLIB2.C < prev    next >
Text File  |  1993-06-26  |  20KB  |  831 lines

  1. /*    ---------------------------------------------------------
  2.     Mods by H Moran:
  3.  
  4.     In case you wish to adopt some but not all of the mods:
  5.     Lines modified by HRM marked with comment 'HRM mod'
  6.     Lines added by HRM marked with comment 'HRM'
  7.  
  8.  
  9.     1) added functions: for list reader and punch devices
  10.  
  11.         lprintf pprintf        -- list and punch devices
  12.         rscanf            -- reader device
  13.         rgets            -- reader device
  14.         lputs   pputs        -- list and punch devices
  15.         lputc   pputc        -- list and punch devices
  16.         rgetc            -- reader device
  17.  
  18.     2) sprintf() modified to use '0' for left fill char
  19.        when radix is not decimal.
  20.  
  21.     3) binary field spec added to sprintf() and sscanf()
  22.        spec used is %b
  23.  
  24.     4) pad char for non-decimal numeric fields in sprintf()
  25.        changed to '0'
  26.  
  27.     5) printing of a..f changed to A..F in _uspr()
  28.  
  29.     6) fgets() fixed to remember reception of 0x1a
  30.        and handle it as EOF. See the one caveat in
  31.        the modified comments.
  32.     -------------------------------------------------------
  33. */
  34.  
  35. /*
  36.     This file contains the source for the following
  37.     library functions:
  38.  
  39.     printf **    fprintf    **    sprintf *
  40.     scanf        fscanf        sscanf
  41.     gets        fgets
  42.     puts        fputs
  43.     swapin ***
  44.  
  45.     *) rewritten for 1.31
  46.     **) work differently since they use the new "sprintf"
  47.     ***) brand new for 1.31
  48.  
  49.     An alternate version of "sprintf" is given in the file
  50.     FLOAT.C for use with floating point numbers; see FLOAT.C
  51.     for details. Note that "sprintf" is used by "printf", so
  52.     this really amounts to an alternate version of "printf",
  53.     too.
  54.  
  55.     Note that all the upper-level formatted I/O functions
  56.     ("printf", "fprintf", "scanf", and "fscanf") now use
  57.     "sprintf" and "sscanf" for doing conversions. While
  58.     this leads to very structured source code, it also
  59.     means that calls to "scanf" and "fscanf" must process
  60.     ALL the information on a line of text; if the format
  61.     string runs out and there is still text left in the
  62.     line being processed, the text will be lost (i.e., the
  63.     NEXT scanf or fscanf call will NOT find it.)
  64.  
  65.     Also note that temporary work space is declared within
  66.     each of the high-level functions as a one-dimensional
  67.     character array. The length limit on this array is
  68.     presently set to 132 by the #define MAXLINE statement;
  69.     if you intend to create longer lines through printf,
  70.     fprintf, scanf, or fscanf calls, be SURE to raise this
  71.     limit by changing the #define statement.
  72.  
  73.     Some misc. comments on hacking text files with CP/M:
  74.     The conventional CP/M text format calls for each
  75.     line to be terminated by a CR-LF combination. In the
  76.     world of C programming, though, we like to just use
  77.     a single LF (also called a newline) to terminate
  78.     lines. AND SO, the functions which deal with reading
  79.     and writing text from disk files to memory and vice-
  80.     versa ("fgets", "fputs") take special pains to convert
  81.     CR-LF combinations into single '\n' characters when
  82.     reading from disk ("fgets"), and convert '\n' char-
  83.     acters to CR-LF combinations when writing TO disk
  84.     ("fputs"). This allows the C programmer to do things
  85.     in style, dealing only with a single line terminator,
  86.     while maintaining compatibility with the CP/M text
  87.     format (so that, for example, a text file can be
  88.     "type"d under the CCP.)
  89.     To confuse matters further, the "gets" function
  90.     (which simply buffers up a line of console input)
  91.     terminates a line with '\0' (a zero byte) instead
  92.     of CR or LF. Thus, if you wanted to read in lines
  93.     of input from the console and write them to a file,
  94.     you'd have to manually put out the CR and LF at the
  95.     end of every line. Oh, and don't forget the 0x1a
  96.     (control-Z) at the end of the file! Hey, kiddies,
  97.     isn't CP/M fun to work with???
  98.     Also, watch out when reading in text files using
  99.     "getc". While a text file is USUALLY terminated
  100.     with a control-Z, it MAY NOT BE if the file ends
  101.     on an even sector boundary. This means that there
  102.     are two possible return values from "getc" which
  103.     signal and EOF: 0x1a (control-Z), and -1 (or 255
  104.     if you assign it to a char variable.)
  105. */
  106.  
  107.  
  108. #define RAM 0        /* start of CP/M RAM area */
  109. #define MAXLINE 132    /* maximum length of text line */
  110. #define EOF -1        /* End of file val returned by getc */
  111. #define NULL 0        /* Returned by fgets on EOF */
  112.  
  113. char toupper(), isdigit();
  114.  
  115. struct buf {
  116.     int fd;
  117.     int nleft;
  118.     char *nextp;
  119.     char buff[128];
  120.  };
  121.  
  122. /*
  123.     printf
  124.  
  125.     usage:
  126.         printf(format, arg1, arg2, ...);
  127.     
  128.     Note that since the sprintf function is used to
  129.     form the output string and then puts is used to
  130.     actually print it out, care must be taken to 
  131.     avoid generating null (zero) bytes in the output,
  132.     since such a byte will terminate printing of the
  133.     string by puts. Thus, a statment such as:
  134.         printf("%c foo",'\0');
  135.     would print nothing at all.
  136.     See the "sprintf" documentation, below, for more info.
  137. */
  138.  
  139. printf(format)
  140. char *format;
  141. {
  142.     char line[MAXLINE];
  143.     _mvl();
  144.     sprintf(line,format);
  145.     puts(line);
  146. }
  147.  
  148.  
  149. /*
  150.     fprintf:
  151.     Like printf, except that the first argument is
  152.     a pointer to a buffered I/O buffer, and the text
  153.     is written to the file described by the buffer:
  154.     (-1 returned on error)
  155.     usage:
  156.         fprintf(iobuf, format, arg1, arg2, ...);
  157. */
  158.  
  159. fprintf(iobuf,format)
  160. char *format;
  161. struct buf *iobuf;
  162. {
  163.     char text[MAXLINE];
  164.     sprintf(text);
  165.     return fputs(text,iobuf);
  166. }
  167.  
  168.  
  169. /*
  170.     fscanf:
  171.     Like scanf, except that the first argument is
  172.     a pointer to a buffered input file buffer, and
  173.     the text is taken from the file instead of from
  174.     the console.
  175.     Usage:
  176.         fscanf(iobuf, format, ptr1, ptr2, ...);
  177.     Returns number of items matched (zero on EOF.)
  178.     Note that any unprocessed text is lost forever. Each
  179.     time scanf is called, a new line of input is gotten
  180.     from the file, and any information left over from
  181.     the last call is wiped out. Thus, the text in the
  182.     file must be arranged such that a single call to
  183.     fscanf will always get all the required data on a
  184.     line.
  185. */
  186.  
  187. int fscanf(iobuf,format,arg1)
  188. char *format;
  189. struct buf *iobuf;
  190. {
  191.     char text[MAXLINE];
  192.     if (!fgets(text,iobuf)) return 0;
  193.     return sscanf(text,format,arg1);
  194. }
  195.  
  196.  
  197. /*
  198.     scanf:
  199.     This one accepts a line of input text from the
  200.     console, and converts the text to the required
  201.     binary or alphanumeric form (see Kernighan &
  202.     Ritchie for a more thorough description):
  203.     Usage:
  204.         scanf(format, ptr1, ptr2, ...);
  205.     Returns number of items matched.
  206.     Since a new line of text must be entered from the
  207.     console each time scanf is called, any unprocessed
  208.     text left over from the last call is lost forever.
  209.     This is a difference between BDS scanf and UNIX
  210.     scanf. Another is that the field width specification
  211.     is not supported here.
  212. */
  213.  
  214. scanf(format)
  215. char *format;
  216. {
  217.     char line[MAXLINE];
  218.     _mvl();
  219.     gets(line);
  220.     sscanf(line,format);
  221. }
  222.  
  223.  
  224. /*
  225.     Internal function to move all function arguments
  226.     over one place to the right, to make room for
  227.     a new argument in the first position. This is
  228.     necessary so that, for example, "sprintf" can
  229.     be called from within "printf" without clobbering
  230.     one of the arguments. This is NOT a portable
  231.     feature of BDS C, and in fact represents one of
  232.     the biggest kludges in the package. Oh well; live
  233.     and learn.
  234. */
  235.  
  236. _mvl()
  237. {
  238.     int count, *ptr;
  239.     ptr = (RAM + 0x3f7 + 0x2e);
  240.     count = 23;
  241.     while (count--) *ptr = *--ptr;
  242. }
  243.  
  244.  
  245. /*
  246.     sprintf:
  247.     Like fprintf, except a string pointer is specified
  248.     instead of a buffer pointer. The text is written
  249.     to where the string pointer points.
  250.     Usage:
  251.         sprintf(string,format,arg1, arg2, ...);
  252.  
  253.     This is my latest version of the "sprintf" standard library
  254.     routine. This time, folks, it REALLY IS standard. I've
  255.     tried to make it EXACTLY the same as the version presented
  256.     in Kernighan & Ritchie: right-justification of fields is
  257.     now the default instead of left-justification (you can GET
  258.     left-justification by using a dash in the conversion, as
  259.     specified in the book); the "%s" conversion can take a precision
  260.     now as well as a field width; the "e" and "f" conversions, for
  261.     floating point numbers, are supported in a special version of
  262.     "sprintf" given in source form in the FLOAT.C file. If you do
  263.     a lot of number crunching and wish to have that version be the
  264.     default (it eats up a K or two more than this version), just
  265.     replace this version of sprintf in DEFF.CRL with the one in FLOAT.C,
  266.     using the CLIB program, or else be stuck with always typing in
  267.     "float" on the clink command line...
  268. */
  269.  
  270.  
  271. sprintf(line,format)
  272. char *line, *format;
  273. {
  274.     char _uspr(), c, base, *sptr;
  275.     char wbuf[80], *wptr, pf, ljflag;
  276.     int width, precision,  *args;
  277.     char lpadchr;    /* HRM */
  278.  
  279.     args = (RAM + 0x3fb);
  280.     while (c = *format++)
  281.       if (c == '%') {
  282.         wptr = wbuf;
  283.         precision = 6;
  284.         ljflag = pf = 0;
  285.  
  286.         if (*format == '-') {
  287.             format++;
  288.             ljflag++;
  289.          }
  290.  
  291.         if ( !(width = _gv2(&format))) width++;
  292.  
  293.         if ((c = *format++) == '.') {
  294.             precision = _gv2(&format);
  295.             pf++;
  296.             c = *format++;
  297.          }
  298.  
  299.         lpadchr = '0';/* HRM pad char for non-decimal numeric fields */
  300.         switch(toupper(c)) {
  301.  
  302.         case 'D':    lpadchr = ' ';
  303.                 if (*args < 0) {
  304.                 *wptr++ = '-';
  305.                 *args = -*args;
  306.                 width--;
  307.                 }
  308.  
  309.         case 'U':  base = 10; goto val;
  310.  
  311.         case 'B':  base = 2;  goto val;    /* HRM */
  312.  
  313.         case 'X':  base = 16; goto val;
  314.  
  315.         case 'O':  base = 8;
  316.  
  317.              val:  width -= _uspr(&wptr,*args++,base);
  318.                goto pad;
  319.  
  320.         case 'C':  lpadchr = ' ';    /* HRM */
  321.                *wptr++ = *args++;
  322.                width--;
  323.                goto pad;
  324.  
  325.         case 'S': lpadchr = ' ';    /* HRM */
  326.               if (!pf) precision = 200;
  327.                sptr = *args++;
  328.                while (*sptr && precision) {
  329.                 *wptr++ = *sptr++;
  330.                 precision--;
  331.                 width--;
  332.                 }
  333.  
  334.              pad:  *wptr = '\0';
  335.              pad2: wptr = wbuf;
  336.                if (!ljflag)
  337.                 while (width-- > 0)
  338.                     *line++ = lpadchr;    /* HRM mod */
  339.  
  340.                while (*line = *wptr++)
  341.                 line++;
  342.  
  343.                if (ljflag)
  344.                 while (width-- > 0)
  345.                     *line++ = ' ';
  346.                break;
  347.  
  348.          default:  *line++ = c;
  349.  
  350.          }
  351.       }
  352.       else *line++ = c;
  353.  
  354.     *line = '\0';
  355. }
  356.  
  357. /*
  358.     Internal routine used by "sprintf" to perform ascii-
  359.     to-decimal conversion and update an associated pointer:
  360. */
  361.  
  362. int _gv2(sptr)
  363. char **sptr;
  364. {
  365.     int n;
  366.     n = 0;
  367.     while (isdigit(**sptr)) n = 10 * n + *(*sptr)++ - '0';
  368.     return n;
  369. }
  370.  
  371.  
  372. /*
  373.     Internal function which converts n into an ASCII
  374.     base `base' representation and places the text
  375.     at the location pointed to by the pointer pointed
  376.     to by `string'. Yes, you read that correctly.
  377. */
  378.  
  379. char _uspr(string, n, base)
  380. char **string;
  381. unsigned n;
  382. {
  383.     char length;
  384.     if (n<base) {
  385.         *(*string)++ = (n < 10) ? n + '0' : n+('A'-10);/* HRM mod */
  386.         return 1;
  387.     }
  388.     length = _uspr(string, n/base, base);
  389.     _uspr(string, n%base, base);
  390.     return length + 1;
  391. }
  392.  
  393.  
  394. /*
  395.     gets:
  396.     Accept an input line from the console, and
  397.     store it at the location pointed to by the
  398.     character pointer argument.
  399.     The newline is NOT included as part of the
  400.     returned text; i.e., typing "abc" and hitting
  401.     carriage-return will result in the string:
  402.     "abc\0"
  403. */
  404.  
  405. gets(s)
  406. char *s;
  407. {
  408.     char c, *temp;
  409.     int count, i;
  410.     temp = s;
  411. start:    count = 0;
  412.     s = temp;
  413.     while ((c=getchar()) != '\n') 
  414.     switch(c) {
  415.      case 0x15:
  416.         putchar('\n');
  417.         goto start;
  418.      case 0x7f:
  419.         if (!count) break;
  420.         --count;
  421.         --s;
  422.         putchar(0x08); putchar(' '); putchar(0x08);
  423.         break;
  424.      case 0x12:
  425.         putchar('\n');
  426.         for (i=0; i<count; ++i) putchar(temp[i]);
  427.         break;
  428.      default:
  429.         *s++ = c;
  430.         ++count;
  431.     }
  432.     *s = 0;
  433.     return temp;
  434. }
  435.  
  436.  
  437. /*
  438.     puts:
  439.     Write out the given string to the console:
  440. */
  441.  
  442. puts(s)
  443. char *s;
  444. {
  445.     while (*s) putchar(*s++);
  446. }
  447.  
  448.  
  449. /*
  450.     fgets:
  451.     This next function is like "gets", except that
  452.     the line is taken from a buffered input file instead
  453.     of from the console. This one is a little tricky
  454.     due to the CP/M convention of having a carriage-
  455.     return AND a linefeed character at the end of every
  456.     text line. In order to make text easier to deal with
  457.     under C programs, this function (fgets) automatically
  458.     strips off the CR from any CR-LF combinations that
  459.     come in from the file. Any CR characters not im-
  460.     mediately followed by LF are left intact. The LF
  461.     is included as part of the string, and is followed
  462.     by a null byte.
  463.     Note that there is no limit to how long a line
  464.     can be here; care should be taken to make sure the
  465.     string pointer passed to fgets points to an area
  466.     large enough to accept any possible line length
  467.     (a line must be terminated by a newline (LF, or '\n')
  468.     character before it is considered complete.)
  469.  
  470.     comment below modified by HRM
  471.  
  472.     The value NULL (defined to be 0 here) is returned
  473.     on EOF. If 0x1a is encountered, the string is considered
  474.     terminated and the 0x1a is pushed bak using unget().
  475.     Note that although unget() will return an error of NULL
  476.     this routine does not bother to check because that can
  477.     happen only with multiple pushbacks and this routine
  478.     will never push back more than a single 0x1a. The next
  479.     invocation of getc() will retrieve the 0x1a with as the
  480.     first char of the string (which is recognized as EOF)
  481.     This means you must not interleave calls to getc() and
  482.     fgets() unless you explicitly handle the case of a 0x1a
  483.     received from getc().
  484.  
  485. */
  486.  
  487. char *fgets(s,iobuf)
  488. char *s;
  489. struct buf *iobuf;
  490. {
  491.     int count, c;
  492.     char *cptr;
  493.     count = (MAXLINE + 1);
  494.     cptr = s;
  495.     while (count-- && (c = getc(iobuf)) != EOF && (c != 0x1a))
  496.         if ((*cptr++ = c) == '\n') {
  497.           if (cptr>s+1 && *(cptr-2) == '\r') {
  498.             *(cptr-2) = '\n';
  499.             cptr--;
  500.            }
  501.           break;
  502.         }
  503.     *cptr = '\0';
  504.     if ( (c == 0x1a) ) {    /* HRM */
  505.       if ( cptr == s )    /* HRM     left over from    last call */
  506.         return NULL;    /* HRM */
  507.       ungetc(iobuf);    /* HRM */ 
  508.       return s;        /* HRM */
  509.     }            /* HRM */
  510.     return ( (( c==EOF) && (cptr == s)) ? NULL : s );
  511. }
  512.  
  513.  
  514.  
  515. /*
  516.     fputs:
  517.     This function writes a string out to a buffered
  518.     output file. The '\n' character is expanded into
  519.     a CR-LF combination, in keeping with the CP/M
  520.     convention.
  521.     If a null ('\0') byte is encountered before a
  522.     newline is encountered, then there will be NO
  523.     automatic termination character appended to the
  524.     line.
  525.     -1 returned on error.
  526. */
  527.  
  528. fputs(s,iobuf)
  529. char *s;
  530. struct buf *iobuf;
  531. {
  532.     char c;
  533.     while (c = *s++) {
  534.         if (c == '\n') putc('\r',iobuf);
  535.         if (putc(c,iobuf) == -1) return -1;
  536.     }
  537.     return 0;
  538. }
  539.  
  540. /*
  541.     sscanf:
  542.     This is the formatted input scanner, taking a
  543.     text string, a format string and a list of pointer
  544.     arguments, appropriate data is picked up from the
  545.     text string and stored where the pointer arguments
  546.     point according to the format string. See K&R.
  547.     Note that the field width specification is not
  548.     supported by this version.
  549. */
  550.  
  551. sscanf(line,format)
  552. char *line, *format;
  553. {
  554.     char sf, c, base, n, *sptr;
  555.     int sign, val, **args;
  556.     args = (RAM + 0x3fb);
  557.     n = 0;
  558.     while (c = *format++) {
  559.        if (isspace(c)) continue;
  560.        if (c != '%') {
  561.         if (c != _igs(&line)) return n;
  562.         else line++;
  563.         }
  564.        else {
  565.         sign = 1;
  566.         base = 10;
  567.         sf = 0;
  568.         if ((c = *format++) == '*') {
  569.             sf++;
  570.             c = *format++;
  571.          }
  572.         switch (toupper(c)) {
  573.            case 'X': base = 16;
  574.                  goto doval;
  575.  
  576.            case 'O': base = 8;
  577.                  goto doval;
  578.  
  579.            case 'B': base = 2;        /* HRM */
  580.                  goto doval;    /* HRM */
  581.  
  582.            case 'D': if (_igs(&line) == '-') {
  583.                 sign = -1;
  584.                 line++;
  585.                   }
  586.        doval:  case 'U': val = 0;
  587.                  if (_bc(_igs(&line),base)== -1)
  588.                 return n;
  589.                  while ((c=_bc(*line++,base))!=255)
  590.                 val = val * base + c;
  591.                  line--;
  592.                  break;
  593.            case 'S': _igs(&line);
  594.                  sptr = *args;
  595.                  while ((c=*line++)&& !isspace(c))
  596.                 if (!sf) *sptr++ = c;
  597.                  if (!sf) {
  598.                 n++;
  599.                 *sptr = '\0';
  600.                 args++;
  601.                 continue;
  602.                   }
  603.            case 'C': if (!sf) {
  604.                 poke(*args++, *line);
  605.                 n++;
  606.                  }
  607.                  line++;
  608.                  continue;
  609.            default:  return n;
  610.          }
  611.         if (!sf) {
  612.             **args++ = val * sign;
  613.             n++;
  614.          }
  615.     }}
  616.     return n;
  617. }
  618.  
  619. /*
  620.     Internal function to position the character
  621.     pointer argument to the next non white-space
  622.     character in the string:
  623. */
  624.  
  625. _igs(sptr)
  626. char **sptr;
  627. {
  628.     char c;
  629.     while (isspace(c = **sptr)) ++*sptr;
  630.     return (c);
  631. }
  632.  
  633.  
  634. /*
  635.     Internal function to convert character c to value
  636.     in base b , or return -1 if illegal character for that
  637.     base:
  638. */
  639.  
  640. _bc(c,b)
  641. char c,b;
  642. {
  643.     if ((c = toupper(c)) > '9') c -= 55;
  644.                  else   c -= 0x30;
  645.     return (c > b-1) ? -1 : c;
  646. }
  647.  
  648.  
  649. /*
  650.     swapin:
  651.     This is the swapping routine, to be used by the root
  652.     segment to swap in a code segment in the area of memory
  653.     between the end of the root segment and the start of the
  654.     external data area. See the document "SWAPPING.DOC" for
  655.     detailed info on the swapping scheme.
  656.  
  657.     Returns -1 on error, 0 if segment swapped in OK.
  658.  
  659.     This version does not check to make sure that the code
  660.     yanked in doesn't overlap into the extenal data area (in
  661.     the interests of keeping the function short.) But, if you'd
  662.     like swapin to check for such problems, note that memory 
  663.     locations ram+115h and ram+116h contain the 16-bit address
  664.     of the base of the external data area (low order byte first,
  665.     as usual.) By rewriting swapin to read in one sector at a time
  666.     and check the addresses, accidental overlap into the data area
  667.     can be avoided.
  668. */
  669.  
  670. swapin(name,addr)
  671. char *name;        /* the file to swap in */
  672. {
  673.     int fd;
  674.     if (( fd = open(name,0)) == -1) {
  675.         printf("Swapin: cannot open %s\n",name);
  676.         return -1;
  677.     }
  678.     if ((read(fd,addr,9999)) < 0) {
  679.         printf("Swapin: read error on %s\n",name);
  680.         return -1;
  681.     }
  682.     return 0;
  683. }
  684.  
  685. /* HRM -------- all lines below added by H Moran -------- */
  686.  
  687.  
  688.  
  689.  
  690. /*
  691.     formatted output to list device
  692.  
  693.     usage:
  694.         lprintf(format, arg1, arg2, ...);
  695. */
  696.  
  697. lprintf(format)        /* formatted print to list device */
  698.     char *format;
  699.     {
  700.     char line[MAXLINE];
  701.  
  702.     _mvl();
  703.     sprintf(line,format);
  704.     lputs(line);
  705.     }
  706.  
  707.  
  708.  
  709.  
  710.  
  711. /*
  712.     formatted print to punch device
  713.  
  714.     usage:
  715.         fprintf(iobuf, format, arg1, arg2, ...);
  716. */
  717.  
  718. pprintf(format)
  719.     char *format;
  720.     {
  721.     char text[MAXLINE];
  722.     sprintf(text);
  723.     pputs(text);
  724.     }
  725.  
  726.  
  727. /*
  728.     formatted scan of reader device
  729.  
  730.     Usage:
  731.         rscanf(format, ptr1, ptr2, ...);
  732. */
  733.  
  734. rscanf(format,arg1)
  735.     char *format;
  736.     {
  737.     char text[MAXLINE];
  738.     if ( ! rgets(text) )
  739.       return 0;
  740.     return sscanf(text,format,arg1);
  741.     }
  742.  
  743.  
  744.  
  745. /*
  746.     Accept an input line from the reader device, and
  747.     store it at the location pointed to by the
  748.     character pointer argument.
  749.     The newline is NOT included as part of the
  750.     returned text; i.e., receiving "abc" and carriage-return
  751.     will result in the string:    "abc\0"
  752. */
  753.  
  754. rgets(s)
  755.     char *s;
  756.     {
  757.     char c,*temp;
  758.     int count, i;
  759.     char rgetc();
  760.  
  761.     temp = s;
  762.     for( count=0; (c=rgetc()) != '\n'; count++ )
  763.       *s++ = c;
  764.     *s='\0';
  765.     return temp;
  766.     }
  767.  
  768.  
  769. /*
  770.     Write out the given string to the list device
  771. */
  772.  
  773. lputs(s)
  774.     char *s;
  775.     {
  776.     while ( *s )
  777.       lputc(*s++);
  778.     }
  779.  
  780.  
  781.  
  782.  
  783. /*
  784.     Write out the given string to the punch device
  785. */
  786.  
  787. pputs(s)
  788.     char *s;
  789.     {
  790.     while ( *s )
  791.       pputc(*s++);
  792.     }
  793.  
  794.  
  795.  
  796.  
  797. /*
  798.     read a char from the reader device
  799. */
  800.  
  801. rgetc()
  802.     {
  803.     return bios(6,0) & 255;
  804.     }
  805.  
  806.  
  807.  
  808. /*
  809.     send a char to the punch device
  810. */
  811.  
  812. pputc(c)
  813.     char c;
  814.     {
  815.     return bios(5,c) & 255;
  816.     }
  817.  
  818.  
  819.  
  820. /*
  821.     send a char to the list device
  822. */
  823.  
  824. lputc(c)
  825.     char c;
  826.     {
  827.     return bios(4,c) & 255;
  828.     }
  829.  
  830.  
  831.